
#include "Base\Settings.h"

#define DefaultSettingFileHeader \
"// Capitalization is very important.\n\
// Spaces are very important.\n\
// Just... Formatting is very important.\n\
// Colors are char4 rgba (0-255)."

#define STSTP StringToSettingTypePair
#define STTSP SettingTypeToStringPair

#define AddSettingType(a)		Setting::m_StringToSettingTypeMap.insert(Setting::STSTP(std::string(#a), Setting::Type::a));		\
								Setting::m_SettingTypeToStringMap.insert(Setting::STTSP(Setting::Type::a, std::string(#a)))
#define AddVecSettingType(a)	Setting::m_StringToSettingTypeMap.insert(Setting::STSTP(std::string(#a), Setting::Type::a));		\
								Setting::m_SettingTypeToStringMap.insert(Setting::STTSP(Setting::Type::a, std::string(#a)));		\
								Setting::m_StringToSettingTypeMap.insert(Setting::STSTP(std::string(#a"2"), Setting::Type::a##2));	\
								Setting::m_SettingTypeToStringMap.insert(Setting::STTSP(Setting::Type::a##2, std::string(#a"2")));	\
								Setting::m_StringToSettingTypeMap.insert(Setting::STSTP(std::string(#a"3"), Setting::Type::a##3));	\
								Setting::m_SettingTypeToStringMap.insert(Setting::STTSP(Setting::Type::a##3, std::string(#a"3")));	\
								Setting::m_StringToSettingTypeMap.insert(Setting::STSTP(std::string(#a"4"), Setting::Type::a##4));	\
								Setting::m_SettingTypeToStringMap.insert(Setting::STTSP(Setting::Type::a##4, std::string(#a"4")))

#define AddSettingTypeLoadSwitch(_SettingType, _Type, _ConversionFuncType, _ConversionFunc)				\
	case Setting::Type::_SettingType:																	\
	{																									\
		_Type val = (_Type)Settings::ParseType<_ConversionFuncType>(valStr, _ConversionFunc);			\
		Settings::SetSetting<_Type>(name, val, Setting::Type::_SettingType);							\
	}																									\
	break
#define AddVecSettingTypeLoadSwitch(_SettingType, _Type, _Num, _ConversionFuncType, _ConversionFunc)	\
	case Setting::Type::_SettingType:																	\
	{																									\
		_Type val = Settings::ParseVecType<_Type, _ConversionFuncType>(valStr, _Num, _ConversionFunc);	\
		Settings::SetSetting<_Type>(name, val, Setting::Type::_SettingType);							\
	}																									\
	break
#define AddSettingTypeSaveSwitch(_SettingType, _Type, _FloatOrInt)										\
	case Setting::Type::_SettingType:																	\
	{																									\
		valueStr = Settings::Stringify##_FloatOrInt##Type<_Type>(setting->GetValue<_Type>());			\
	}																									\
	break
#define AddVecSettingTypeSaveSwitch(_SettingType, _Type, _Num, _FloatOrInt)								\
	case Setting::Type::_SettingType:																	\
	{																									\
		valueStr = Settings::Stringify##_FloatOrInt##VecType<_Type>(setting->GetValue<_Type>(), _Num);	\
	}																									\
	break

#define DefaultCfgFileName "defaultCfg.cfg"

///////////////////////////////////////////////////////////
//        ///  //////  /        ///  ///////  ///        //
//  //////  /  //////  /  //////  /  ///////  /  //////////
//        ///  //////  /        ///  ///////  /  //////////
//  /////////  //////  /  //////  /  ///////  /  //////////
//  ///////////      ///        ///        /  ///        //
///////////////////////////////////////////////////////////

bool ShRp::Base::Settings::Init()
{
	AddSettingType(Color_t);
	AddVecSettingType(Int);
	AddVecSettingType(Float);
	AddVecSettingType(Char);
	AddVecSettingType(Short);
	AddSettingType(String);

	return true;
}

void ShRp::Base::Settings::Terminate()
{

}

void ShRp::Base::Settings::Load( const char* _CfgFileName )
{
	char filePath[256];
	sprintf_s(filePath, 256, "../settings/%s", _CfgFileName);
	Log("Loading config from file \"%s\".\n", filePath);
	if(!FileExists(filePath))
	{
		Warn("Specified config file not found, loading default (%s).\n", DefaultCfgFileName);
		sprintf_s(filePath, 256, "../settings/%s", DefaultCfgFileName);
	}
	std::ifstream file(filePath);
	if(file.is_open())
	{
		std::string line;
		int lineNumber = 0;
		while(!file.eof())
		{
			getline(file, line);
			Settings::ParseLine(line, lineNumber);
			lineNumber++;
		}
		// Close file.
		file.close();
	}
	else
	{
		Error("Specified config file could not be opened.\n");
	}
}

void ShRp::Base::Settings::Save( const char* _CfgFileName )
{
	char filePath[256];
	sprintf_s(filePath, 256, "../settings/%s", _CfgFileName);
	Log("Saving config to file \"%s\".\n", filePath);
	std::ofstream file(filePath);
	if(file.is_open())
	{
		file << DefaultSettingFileHeader << std::endl;
		for(StringSettingMap::iterator settingIt = m_Settings.begin(); settingIt != m_Settings.end(); ++settingIt)
		{
			Setting* setting = settingIt->second;
			std::string settingName = settingIt->first;

			Setting::SettingTypeToStringMap::iterator typeToStrIt = Setting::m_SettingTypeToStringMap.find(setting->GetType());
			if(typeToStrIt == Setting::m_SettingTypeToStringMap.end())
			{
				Warn("Setting \"%s\" has invalid setting type.\n", settingName);
				continue;
			}
			std::string typeStr = typeToStrIt->second;

			std::string valueStr = "";
			switch(setting->GetType())
			{
			AddVecSettingTypeSaveSwitch(Color_t, Color, 4, Int);
			AddSettingTypeSaveSwitch(Int, int, Int);
			AddVecSettingTypeSaveSwitch(Int2, int2, 2, Int);
			AddVecSettingTypeSaveSwitch(Int3, int3, 3, Int);
			AddVecSettingTypeSaveSwitch(Int4, int4, 4, Int);

			AddSettingTypeSaveSwitch(Float, float, Float);
			AddVecSettingTypeSaveSwitch(Float2, float2, 2, Float);
			AddVecSettingTypeSaveSwitch(Float3, float3, 3, Float);
			AddVecSettingTypeSaveSwitch(Float4, float4, 4, Float);
			AddSettingTypeSaveSwitch(Char, char, Int);
			AddVecSettingTypeSaveSwitch(Char2, char2, 2, Int);
			AddVecSettingTypeSaveSwitch(Char3, char3, 3, Int);
			AddVecSettingTypeSaveSwitch(Char4, char4, 4, Int);
			AddSettingTypeSaveSwitch(Short, char, Int);
			AddVecSettingTypeSaveSwitch(Short2, short2, 2, Int);
			AddVecSettingTypeSaveSwitch(Short3, short3, 3, Int);
			AddVecSettingTypeSaveSwitch(Short4, short4, 4, Int);
			case Setting::Type::String:
				{
					valueStr = setting->GetValue<std::string>();
				}
				break;
			}
			file << typeStr << " " << settingName << " = " << valueStr << std::endl;
		}
	}
	else
	{
		Error("Specified config file could not be opened.\n");
	}
}

void ShRp::Base::Settings::ParseLine( std::string _Line, int _LineNumber )
{
	{
	if(_Line[0] == '/' && _Line[1] == '/' || _Line.length() < 1)
		return;

	std::string typeStr = _Line.substr(0, _Line.find(' '));
	Setting::StringToSettingTypeMap::iterator typeIt = Setting::m_StringToSettingTypeMap.find(typeStr);
	if(typeIt == Setting::m_StringToSettingTypeMap.end())
	{
		Warn("Unknown setting type found in config file: \"%s\" on line %i.\n", typeStr.c_str(), _LineNumber);
		return;
	}
	Setting::Type::E type = typeIt->second;
	std::string valStr = _Line.substr(_Line.find("= ")+2);
	std::string name = _Line.substr(0, _Line.find(" = "));
	name = name.substr(_Line.find(' ')+1);
	switch(type)
	{
	AddVecSettingTypeLoadSwitch(Color_t, Color, 4, int, atoi);
	AddSettingTypeLoadSwitch(Int, int, int, atoi);
	AddVecSettingTypeLoadSwitch(Int2, int2, 2, int, atoi);
	AddVecSettingTypeLoadSwitch(Int3, int3, 3, int, atoi);
	AddVecSettingTypeLoadSwitch(Int4, int4, 4, int, atoi);
	AddSettingTypeLoadSwitch(Float, float, double, atof);
	AddVecSettingTypeLoadSwitch(Float2, float2, 2, double, atof);
	AddVecSettingTypeLoadSwitch(Float3, float3, 3, double, atof);
	AddVecSettingTypeLoadSwitch(Float4, float4, 4, double, atof);
	AddSettingTypeLoadSwitch(Char, char, int, atoi);
	AddVecSettingTypeLoadSwitch(Char2, char2, 2, int, atoi);
	AddVecSettingTypeLoadSwitch(Char3, char3, 3, int, atoi);
	AddVecSettingTypeLoadSwitch(Char4, char4, 4, int, atoi);
	AddSettingTypeLoadSwitch(Short, char, int, atoi);
	AddVecSettingTypeLoadSwitch(Short2, short2, 2, int, atoi);
	AddVecSettingTypeLoadSwitch(Short3, short3, 3, int, atoi);
	AddVecSettingTypeLoadSwitch(Short4, short4, 4, int, atoi);
	case Setting::Type::String:
		{
			Settings::SetSetting<std::string>(name, valStr, Setting::Type::String);
		}
		break;
	}
	int dbg = 0;
	}
	int dbg2 = 0;
}
////////////////////////////////////////////////////////////////
//      ///      ///  /  //////  ///    ///          /        //
//  ////  /  ////  /  /  //////  /  ////  /////  /////  ////////
//      ///      ///  ///  //  ///        /////  /////      ////
//  ///////  //  ///  ///  //  ///  ////  /////  /////  ////////
//  ///////  ////  /  /////  /////  ////  /////  /////        //
////////////////////////////////////////////////////////////////

ShRp::Base::StringSettingMap ShRp::Base::Settings::m_Settings;
